class Animal {
    constructor(public name:string, public age:number) {}
}
class Person {
    constructor(public name:string, public age:number) {}
}
// type IClazz = new (name: string, age: number) => any
interface IClazz<T> {
    new (name: string, age: number): T  
} 
function createInstance<T>(target:IClazz<T>, name:string, age:number) {
   return new target(name, age);
}
// ts中使用的时候确定类型 可以通过范型（传递的类型）T K U N M O P
const animal = createInstance<Animal>(Animal, 'Cat', 18);
const person = createInstance(Person, 'John', 18); // 可以自动推导

// 根据提供的数据生成对应长度的数组

function createArray<U>(len:number, val:U) {
  let result:U[] = [];
  for(let i = 0; i < len; i++) {
    result.push(val);
  }
  return result;
}

let r = createArray(3, 'abc');
// 2个范型
// function swap<T, K>(tuple:[T, K]):[K,T] {
//     return [tuple[1], tuple[0]]
// }
// type ISwap = <T, K>(tuple:[T, K]) => [K,T] // 此类型可以复用
interface ISwap {
    <T, K>(tuple: [T, K]):[K,T]
}
let swap:ISwap = (tuple) => {
    return [tuple[1], tuple[0]]
} 
swap([123, 'abc']);

// 范型使用的时候传递类型， 可以直接推导，但是内部调用的时候没有确定类型
type ICallback<T> = (item: T, index: number) => void;
type IforEach = <T>(arr: T[], callback:ICallback<T>) => void;

const forEach: IforEach = (arr, callback) => {
    for(let i = 0; i < arr.length; i++) {
        callback(arr[i], i);
    }
}

forEach([1, 2, 3, "a", "b", "c"], function(item, index){});

// 写在前面 就是表示使用类型的时候传参，写到函数的前面意味着调用函数的时候传递参数

// 范型是有默认值的
// 在使用一些联合类型的时候会使用范型

type Union<T = boolean> = T | number | string;
let union:Union<boolean> & {} = true;

// 泛型约束 要求传递的参数必须符合要求 xxx extends 要求  A extends B A是B的子类型或者同类型

function handle<T extends string|number>(val: T): T {
    return val
}

handle('abc');

interface IWithLen {
    length: number;
}

// 
function handle2<T extends IWithLen>(val: T) {
    return val.length
}
handle2({a:1, length: 3});

function getVal<T, K extends keyof T>(obj:T, key: K) {
    return obj[key]
}
getVal({name:'jw', age: 30}, 'age');
// 通过泛型坑位 来占位置
interface ILoginData {
    token: string,
    roles: number[]
}
interface ILoginResponse<T> {
    code: number,
    message?: string,
    data: T
}
function toLogin():ILoginResponse<ILoginData> {
    return {
        code: 200,
        data: {
            token: "hahahah",
            roles: [1,2,3]
        }
    }
}

// 获取最大值

class MyArray<T> {
    private arr:T[] = [];
    set(val:T) {
        this.arr.push(val);
    }
    getMax():T {
        let arr = this.arr;
        let max = arr[0];
        for(let i = 1; i < arr.length; i++) {
            let current = arr[i];
            current > max ? max = current: void 0;
        }
        return max;
    }
}

let myArr = new MyArray<number>();
myArr.set(200)
myArr.set(100)
myArr.set(300)

export {}